package com.br4mmie.asciistory.battle;

import java.util.*;

import com.br4mmie.asciistory.*;
import com.br4mmie.asciistory.mission.*;


/**
 * @author Niels
 * Battle Class.
 * Contains the encounter displayed in its creating BattleWindow
 * manages the acting creatures and
 */
public class Battle
{
	private ArrayList<Enemy> enemies; //All enemies in the battle that are currently alive
	private ArrayList<Enemy> slainEnemies; //Enemies that have been Defeated, remembered for the purpose of calculating spoils
	private EncounterPlayer player; //The players representation in the fight.
	private Animation animation; //Current animation being played in the battle
	private CharImage background; //the Battle's background.
	private int currentActor; //Who's turn it is
	private BattleWindow parentwindow;//the creating window
	private String[] messages;//The battle's console messages
	
	private boolean hasAnimation;//used to check if an animation is playing
	/**
	 * Constructor
	 * @param enems ArrayList containing enemytype
	 * @param b Battle background
	 * @param p Representation of player
	 * @param bw Parent BattleWindow
	 */
	Battle(EnemyType[] enems, CharImage b, EncounterPlayer p, BattleWindow bw)
	{
		parentwindow = bw;
		animation = null;
		hasAnimation = false;
		background = b;
		player = p;
		p.setBattle(this);
		enemies = new ArrayList<Enemy>();
		slainEnemies = new ArrayList<Enemy>();
		messages = new String[5];
		
		for(int i=0; i<=4; i++) messages[i] = "";		
				
		for(EnemyType et: enems)
		{
			Enemy e = new Enemy(et, this);
			enemies.add(e);
		}
		setEnemyPositions();
	}
	/**
	 * Calculates the enemy positions on screen
	 */
	private void setEnemyPositions() 
	{
		if(enemies.size() <= 3)
		{
			for(Enemy e : enemies)
			{
				e.setScreenPosX(((ASCIIStoryActivity.getScreenWidth()/(enemies.size()+1))*(enemies.indexOf(e)+1))-((e.getWidth())/2)+((enemies.indexOf(e)-1)*2));
				e.setScreenPosY((ASCIIStoryActivity.getScreenHeight()/2)-(e.getHeight()/2));
			}
		}
		else
		{
			int lines = ((enemies.size()-1)/3)+2;
			//int columwidth = Apl.getScreenWidth()/4;
			int currentline = 0;
			int lineheight = ASCIIStoryActivity.getScreenHeight()/lines;
					
			for(Enemy e: enemies)
			{
				currentline = enemies.indexOf(e)/3;
				if(currentline == lines)
				{
					e.setScreenPosX(((ASCIIStoryActivity.getScreenWidth()/((enemies.size()%3)+1))*((enemies.indexOf(e)%3)+1))-((e.getWidth())/2)+(((enemies.indexOf(e)%3)-1)*2));
					e.setScreenPosY(((lines-1)-(enemies.indexOf(e)/3))-(e.getHeight()/2));
				}
				else
				{
					e.setScreenPosX(((ASCIIStoryActivity.getScreenWidth()/4)*((enemies.indexOf(e)%3)+1))-((e.getWidth())/2)+(((enemies.indexOf(e)%3)-1)*2));
					e.setScreenPosY((((lines-1)-(enemies.indexOf(e)/3))*lineheight)-(e.getHeight()/2));
				}
				
			}
		}
	}
	/**
	 * Geeter/setters
	 * @return player
	 */
	public EncounterPlayer getPlayer() 
	{
		return player;
	}
	public ArrayList<Enemy> getEnemies()
	{
		return enemies;
	}
	public void setAnimation(Animation anim) 
	{
		animation = anim;
		hasAnimation = true;
	}
	/**
	 * Draws the current scene to the given CharImage
	 * @param target
	 */
	public void onDraw(CharImage target)
	{
		//create temporary image to draw the battle to
		CharImage tempImage = new CharImage(background.getWidth(),background.getHeight());
		
		//draw the background
		background.draw(tempImage);
		
		//draw the enemies on the background
		for(Enemy e: enemies)
		{
			e.OnDraw(tempImage);
		}
		//draw the animation
		if(hasAnimation) 
		{
			animation.onDraw(tempImage);
		}
		
		//draw the player
		player.onDraw(tempImage);
		
		//draw the battle status
		drawConsole(tempImage);
		
		//and finally draw our buffer to the target
		tempImage.draw(target);
	}
	
	/**
	 * Draws the battle Console to the given target
	 * @param target CharImage to draw console on
	 */
	private void drawConsole(CharImage target) 
	{
		//temporary image for the console
		CharImage console = new CharImage(ASCIIStoryActivity.getScreenWidth()-21, 9);
		
		//fill the console with a nice white background and a border
		console.fill(' ');
		drawConsoleBorder(console);
		
		//write four messages..
		int y = 1;
		for (String msg: messages)
		{			
			//decrease the number of messages to draw if messages take more than one line
			y += console.drawText(2, y, console.getWidth() - 4, msg) + 1;
			if (y > 6) break;
		}
		
		//and draw the console to the target
		console.draw(target, 2, ASCIIStoryActivity.getScreenHeight()-10);
	}
	/**
	 * Draws the outline for the Console
	 * @param consoleImage CharImage to draw the border on
	 */
	private void drawConsoleBorder(CharImage consoleImage)
	{
		consoleImage.rect('+', 0, 0, consoleImage.getWidth()-1, consoleImage.getHeight()-1);
	}
	/**
	 * Add a message to the battle console
	 * @param message message to put in console
	 */
	public void addMessage(String message)
	{
		//push the messages back to make place for the new one
		for(int i=0; i<4; i++) messages[i] = messages[i+1];
		
		//and finally set the new one
		messages[4] = message;
	}
	/**
	 * Basic loop funtion
	 */
	public void onLoop()
	{
		//update the animation, if there is any
		if(hasAnimation)
		{
			if(animation.isPlaying)
			{
				animation.onLoop();
			}
			else
			{
				//animation finished, now we don't have any
				hasAnimation = false;	
			}
		}
		else
		{		
			if (currentActor >= enemies.size())
			{
				player.act();
			}
			else
			{
				enemies.get(currentActor).act();
			
				for(Enemy e : enemies)
				{
					if(e.getCurrentHP() <= 0)
					{
						e.act();
						slainEnemies.add(e);
					}
				}
				
				currentActor++;
			}
			
			for(Enemy e : slainEnemies)
			{
				if(enemies.contains(e))
				{
					enemies.remove(e);
				}
			}
			if (player.getCurrentHP() <= 0)  defeat();
			if (enemies.isEmpty())			 victory();
		}
	}
	/**
	 * Handles defeat
	 */
	private void defeat() 
	{
		parentwindow.defeat();
	}
	/**
	 * Calculates the rewards for the finished battle and returns a BattleReward containing those
	 * @return BattleReward containing spoils 
	 */
	private BattleReward getWins()
	{
		int totalXP = 0;
		int totalGold = 0;
		ArrayList<Item> loot = new ArrayList<Item>();
		ArrayList<String> kills = new ArrayList<String>();
		
		for(Enemy e :slainEnemies)
		{
			totalXP += e.getXpValue();
			totalGold += e.getGold();
			e.getDrops(loot, (int)(Math.random()*100+1));
			kills.add(e.getName());
		}
		
		return new BattleReward(loot, totalXP, totalGold, kills);
	}
	/**
	 * Victory function, called if player is victorious
	 */
	private void victory() 
	{
		parentwindow.victory(getWins());		
	}
	/**
	 * Give the turn to the first enemy
	 */
	public void setEnemyTurn() 
	{
		currentActor = 0;
	}
}
